package com.helin.helinhealth.common;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.HashMap;
import java.util.Map;

/**
 * 全局异常处理器
 * 
 * <p>
 * 该类用于捕获和处理系统中所有控制器抛出的异常，确保API返回格式统一。
 * 对常见的异常类型提供了不同的处理逻辑，并记录错误日志。
 * </p>
 */
@Slf4j
@RestControllerAdvice(basePackages = {"com.helin.helinhealth.controller"})
public class GlobalExceptionHandler {

    /**
     * 处理参数校验异常
     * 
     * @param ex 方法参数校验异常
     * @param request HTTP请求
     * @return 包含校验错误信息的结果
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handleValidationExceptions(MethodArgumentNotValidException ex, HttpServletRequest request) {
        // 排除文档相关路径
        if (isSwaggerRequest(request)) {
            // 不再抛出异常，而是将异常信息返回
            log.debug("忽略Swagger请求中的参数验证异常");
            return createSwaggerErrorResult(ex.getMessage());
        }
        return handleBindingResult(ex.getBindingResult(), request);
    }
    
    /**
     * 处理绑定异常
     * 
     * @param ex 绑定异常
     * @param request HTTP请求
     * @return 包含绑定错误信息的结果
     */
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(BindException.class)
    public Result handleBindExceptions(BindException ex, HttpServletRequest request) {
        // 排除文档相关路径
        if (isSwaggerRequest(request)) {
            // 不再抛出异常，而是将异常信息返回
            log.debug("忽略Swagger请求中的绑定异常");
            return createSwaggerErrorResult(ex.getMessage());
        }
        return handleBindingResult(ex.getBindingResult(), request);
    }
    
    /**
     * 处理绑定结果
     * 
     * @param bindingResult 绑定结果
     * @param request HTTP请求
     * @return 包含错误信息的结果
     */
    private Result handleBindingResult(BindingResult bindingResult, HttpServletRequest request) {
        Map<String, String> errors = new HashMap<>();
        bindingResult.getAllErrors().forEach(error -> {
            String fieldName = ((FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        
        String path = request.getRequestURI();
        log.error("参数验证失败：{}, 路径: {}", errors, path);
        return Result.custom(400, "参数验证失败", errors, false, path);
    }
    
    /**
     * 处理所有未明确处理的异常
     * 
     * @param ex 异常
     * @param request HTTP请求
     * @return 包含错误信息的结果
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public Result handleAllExceptions(Exception ex, HttpServletRequest request) {
        // 排除文档相关路径
        if (isSwaggerRequest(request)) {
            // 不再抛出异常，而是将异常信息返回
            log.debug("忽略Swagger请求中的通用异常");
            return createSwaggerErrorResult(ex.getMessage());
        }
        
        String path = request.getRequestURI();
        log.error("系统异常：", ex);
        return Result.custom(500, "系统异常: " + ex.getMessage(), null, false, path);
    }
    
    /**
     * 判断是否是Swagger/Knife4j相关请求
     * 
     * @param request HTTP请求
     * @return 是否为Swagger相关请求
     */
    private boolean isSwaggerRequest(HttpServletRequest request) {
        String path = request.getRequestURI();
        return path.contains("/v3/api-docs") 
            || path.contains("/swagger") 
            || path.contains("/doc.html")
            || path.contains("/webjars/")
            || path.contains("/favicon.ico");
    }
    
    /**
     * 创建Swagger错误响应结果
     * 
     * @param message 错误信息
     * @return 结果对象
     */
    private Result createSwaggerErrorResult(String message) {
        return Result.custom(200, "Swagger文档请求", message, true, "/swagger");
    }
} 